﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AnaxibiaStudios.Smug.Internal
{
  public class MethodInfoEx : MemberInfoEx<MethodInfo>
  {
    protected MethodInfoEx(MemberCollection parent) : base(parent, null) { }

    public MethodInfoEx(MemberCollection parent, MethodInfo method)
      : base(parent, method)
    {
      SetModifiers(method);
      Access = ParseAccess(method);
      SetParameters(method.ReturnType, method.GetParameters());
    }

    public override string BuildBody()
    {
      var builder = _parent.Builder;
      string source = "";

      var call = (BaseCall == BaseCall.Null ? string.Empty : (SourceBuilder.Dot + builder.BuildMethodName(Info))) + builder.BuildMethodCallParams(Info, SourceBuilder.OutPrefix);
      source += builder.BuildRedirection(this, builder.BuildGetMethodHandle(this, call, builder.BuildGetExplicitMethod(Info, call)));

      return Scope.Brackets(source);
    }

    protected override string BuildTemplate()
    {
      return _parent.Builder.BuildTemplate(Info.GetGenericArguments());
    }

    public static bool Match(MethodInfoEx a, MethodInfoEx b, bool ignoreAccess)
    {
      if (a == null || b == null)
      {
        return false;
      }

      Func<MethodInfoEx, string> getSig = ex =>
        ex.BuildSignature(new SignatureOptions
        {
          IgnoreAccess = ignoreAccess,
          OverrideText = string.Empty,
          IgnoreParamNames = true
        });

      var aSig = getSig(a);
      var bSig = getSig(b);

      return aSig == bSig;
    }

    protected override bool MatchesNonOverload(MemberInfoEx that)
    {
      var mex = that as MethodInfoEx;
      if (mex == null)
        return false;

      if (ReturnType != mex.ReturnType)
        return false;

      if (mex.Parameters.Length != Parameters.Length)
        return true; //nothing more to check

      for (int i = 0; i < Parameters.Length; i++)
      {
        var ths = Parameters[i];
        var tht = mex.Parameters[i];

        if (ths.Type != tht.Type)
          return true; // safe to report true, sigs are checked first

        if (ths.PassBy != tht.PassBy)
          return false; // uh oh
      }

      return true;
    }

    protected override bool IsOverloadable()
    {
      return true;
    }
  }
}
